package com.tuanzi.loan.business.service.system.impl;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.tuanzi.server.loan_base.constant.LoanRedisKey;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.retry.RetryException;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Maps;
import com.tuanzi.loan.business.entity.system.Dictionary;
import com.tuanzi.loan.business.repository.system.DictionaryRepository;
import com.tuanzi.loan.business.service.system.DictionaryService;
import com.tuanzi.loan.core.aspect.Debug;
import com.tuanzi.loan.core.exception.SystemException;
import com.tuanzi.loan.core.repository.JPABaseRepository;
import com.tuanzi.loan.core.service.BaseServiceImpl;
import com.tuanzi.loan.core.util.GsonUtils;
import com.tuanzi.loan.core.vo.PageSearcher;
import com.tuanzi.loan.vo.request.system.DictionarySearchRequest;
import com.tuanzi.loan.vo.response.system.DictionarySearchResponse;

/**
 * @author Ray 2017/09/21
 */
@Debug
@Service
@Transactional
@Retryable(value = { RetryException.class })
public class DictionaryServiceImpl extends BaseServiceImpl<Dictionary, String> implements DictionaryService {

	@Autowired
	private DictionaryRepository dictionaryRepository;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	@Override
	protected JPABaseRepository<Dictionary, String> getRepository() {
		return dictionaryRepository;
	}
	
	@Override
	public Dictionary findByCodeAndValue1(String code, String value1) {
		return dictionaryRepository.findByCodeAndValue1(code, value1);
	}

	@Override
	public List<Dictionary> findAllByCode(String code) {
		return dictionaryRepository.findAllByCodeAndEnableTrueOrderBySort(code);
	}

	@Override
	public Dictionary findByCodeAndName(String code, String name) {
		return dictionaryRepository.findByCodeAndNameAndEnableTrue(code, name);
	}

	@Override
	public Dictionary findByCode(String code) {
		List<Dictionary> dictionaries = findAllByCode(code);
		if (CollectionUtils.isEmpty(dictionaries)) {
			throw new SystemException("字典编码 : " + code + " 没找到任何对应的字典");
		}

		if (dictionaries.size() > 1) {
			throw new SystemException("字典编码 : " + code + " 存在" + dictionaries.size() + "个字典");
		}
		return dictionaries.get(0);
	}

	@Override
	public String findValueByCodeAndName(String code, String name) {
		return findByCodeAndName(code, name).getValue1();
	}

	@Override
	public Page<DictionarySearchResponse> list(PageSearcher<DictionarySearchRequest> pageSearcher) {
		return dictionaryRepository.list(pageSearcher.getSearchCondition(), pageSearcher.getPageable());
	}

	@Override
	public Map<String, List<Dictionary>> batchFindByCodes(List<String> codes) {
		if (CollectionUtils.isEmpty(codes)) {
			return Maps.newHashMap();
		}
		return dictionaryRepository.findAllByCodes(codes).stream().sorted(Comparator.comparing(Dictionary::getSort)).collect(Collectors.groupingBy(Dictionary::getCode));
	}

	@Override
	public void onRefreshCache() {
		Map<String, List<Dictionary>> dictionaryMaps = findAllEnable().parallelStream().collect(Collectors.groupingBy(Dictionary::getCode, Collectors.mapping(x -> {
			Dictionary dictionary = new Dictionary();
			dictionary.setName(x.getName());
			dictionary.setValue1(x.getValue1());
			dictionary.setValue2(x.getValue2());
			dictionary.setValue3(x.getValue3());
			dictionary.setValue4(x.getValue4());
			dictionary.setSort(x.getSort());
			dictionary.setEnable(null);
			return dictionary;
		}, Collectors.toList())));

		dictionaryMaps.entrySet().parallelStream().forEach(x -> {
			BoundHashOperations hashOperations = stringRedisTemplate.boundHashOps(LoanRedisKey.LOAN_DICTIONARY);
			hashOperations.delete(x.getKey());
			hashOperations.put(x.getKey(), GsonUtils.toJson(x.getValue()));
		});
	}

	@Override
	public Map<String, String> listMapByCode(String code) {
		Map<String /* value */, String /* name */> map = Maps.newHashMap();
		for (Dictionary dictionary : findAllByCode(code)) {
			map.put(dictionary.getValue1(), dictionary.getName());
		}
		return map;
	}
}
